package com.quectel.business.common.visitor;

import com.quectel.business.dms.AccessorUtils;
import com.quectel.business.dms.application.access.accessor.ieg.AbstractIntelligentEntranceGuardAccessor;
import com.quectel.business.dms.application.access.accessor.ieg.model.DeviceFaceSendCmd;
import com.quectel.business.dms.application.access.accessor.ieg.model.DeviceQrCodeGenCmd;
import com.quectel.constant.core.device.DeviceCategoryCodeConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.device.dto.DeviceCategoryDto;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.device.service.DeviceCategoryService;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.core.module.device.service.DeviceTypeService;
import com.quectel.core.module.entranceguard.dto.EntranceGuardAbilityConfigDto;
import com.quectel.core.module.entranceguard.dto.EntranceGuardVisitorApplyRecordDto;
import com.quectel.core.module.entranceguard.dto.VisitorDto;
import com.quectel.core.module.entranceguard.service.EntranceGuardAbilityConfigService;
import com.quectel.core.module.entranceguard.service.EntranceGuardVisitorApplyRecordService;
import com.quectel.core.module.entranceguard.service.VisitorService;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.household.service.HouseholdService;
import com.quectel.core.module.village.service.VillageRoomService;
import com.quectel.sys.module.sys.dto.SysUserDto;
import com.quectel.sys.module.sys.service.SysUserService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @date 2021/12/24 5:05 下午
 */
@Component
@Slf4j
public class ApplyProcessingComponent {

    @DubboReference
    private VisitorService visitorService;
    @DubboReference
    private EntranceGuardVisitorApplyRecordService entranceGuardVisitorApplyRecordService;
    @DubboReference
    private HouseholdService householdService;
    @DubboReference
    private SysUserService sysUserService;
    @DubboReference
    private VillageRoomService villageRoomService;
    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private DeviceTypeService deviceTypeService;
    @DubboReference
    private DeviceCategoryService deviceCategoryService;
    @DubboReference
    private EntranceGuardAbilityConfigService entranceGuardAbilityConfigService;

    public Response<Object> applyHandler(VisitorDto visitorDto
            , EntranceGuardVisitorApplyRecordDto applyRecordDto
            , Byte applyUserType, Long applyUserId) {

        List<DeviceDto> bindDevices = deviceService.queryAtlasBindDevices(applyRecordDto.getRoomId());
        DeviceCategoryDto deviceCategoryDto = deviceCategoryService.selectCacheByCode(DeviceCategoryCodeConstants.INTELLIGENT_ENTRANCE_GUARD);
        List<DeviceDto> gateBindDeviceList = bindDevices.stream().filter(o -> deviceCategoryDto.getId().equals(o.getDeviceCategoryId())).collect(Collectors.toList());
        if (gateBindDeviceList == null || gateBindDeviceList.size() <= 0) {
            return Response.error("未找到该房间及房间所属单元、小区绑定的门禁设备");
        }

        Map<Long, List<DeviceDto>> bindDeviceMap = gateBindDeviceList.stream().collect(Collectors.groupingBy(DeviceDto::getDeviceTypeId));

        Map<DeviceTypeDto, List<DeviceDto>> faceAvailableOrAllDevices = new HashMap<>();
        Map<DeviceTypeDto, List<DeviceDto>> qrCodeAvailableDevices = new HashMap<>();

        for (Long aLong : bindDeviceMap.keySet()) {
            DeviceTypeDto deviceTypeDto = deviceTypeService.selectById(aLong);
            if (deviceTypeDto == null) {
                continue;
            }
            EntranceGuardAbilityConfigDto entranceGuardAbilityConfigDto = entranceGuardAbilityConfigService.selectCacheByDeviceTypeId(deviceTypeDto.getId());
            if (Objects.equals(entranceGuardAbilityConfigDto.getFaceCapability(), SystemConstants.NORMAL)
            ) {
                //有人脸
                faceAvailableOrAllDevices.put(deviceTypeDto, bindDeviceMap.get(aLong));
            }
            if (Objects.equals(entranceGuardAbilityConfigDto.getQrcodeCapability(), SystemConstants.NORMAL)) {
                //有二维码的权限
                qrCodeAvailableDevices.put(deviceTypeDto, bindDeviceMap.get(aLong));
            }

        }

        if (faceAvailableOrAllDevices.keySet().size() <= 0 && qrCodeAvailableDevices.keySet().size() <= 0) {
            return Response.error("门禁设备不具备人脸或二维码授权");
        }

        // 授权过程
        Set<Long> deviceIds = sendFace(faceAvailableOrAllDevices);
        String qrCode = null;
        if (qrCodeAvailableDevices.keySet().size() == 1) {
            // 具备二维码授权的门禁大于两种类型，不授权
            for (Map.Entry<DeviceTypeDto, List<DeviceDto>> deviceTypeDtoListEntry : qrCodeAvailableDevices.entrySet()) {
                deviceIds.addAll(deviceTypeDtoListEntry.getValue().stream().map(DeviceDto::getId).collect(Collectors.toSet()));
                qrCode = genQrCode(deviceTypeDtoListEntry.getKey(), deviceTypeDtoListEntry.getValue());
                break;
            }
        }

        if (EntranceGuardVisitorApplyRecordDto.ApplyUserTypeEnum.ADMIN.getType().equals(applyUserType)) {
            SysUserDto sysUserDto = sysUserService.selectById(applyUserId);
            applyRecordDto.setApplyUserId(sysUserDto.getId());
            applyRecordDto.setApplyUserType(EntranceGuardVisitorApplyRecordDto.ApplyUserTypeEnum.ADMIN.getType());
            applyRecordDto.setApplyUsername(sysUserDto.getUsername());
        } else {
            HouseholdDto householdDto = householdService.selectById(applyUserId);
            applyRecordDto.setApplyUserId(householdDto.getId());
            applyRecordDto.setApplyUserType(EntranceGuardVisitorApplyRecordDto.ApplyUserTypeEnum.HOUSEHOLD.getType());
            applyRecordDto.setApplyUsername(householdDto.getName());
        }

        Long save = visitorService.save(visitorDto);
        applyRecordDto.setVisitorId(save);
        applyRecordDto.setQrCode(qrCode);
        applyRecordDto.setDeviceIds(JacksonUtils.toJsonString(deviceIds));
        entranceGuardVisitorApplyRecordService.save(applyRecordDto);
        return Response.ok();
    }

    private Set<Long> sendFace(Map<DeviceTypeDto, List<DeviceDto>> faceAvailableOrAllDevices) {
        Set<Long> idSet = new HashSet<>();
        for (DeviceTypeDto deviceTypeDto : faceAvailableOrAllDevices.keySet()) {

            List<DeviceDto> deviceDtos = faceAvailableOrAllDevices.get(deviceTypeDto);
            List<DeviceFaceSendCmd.DeviceInfo> list = deviceDtos.stream().map(o -> {
                DeviceFaceSendCmd.DeviceInfo deviceInfo = new DeviceFaceSendCmd.DeviceInfo();
                deviceInfo.setDeviceUniqueId(o.getUniqueId());
                idSet.add(o.getId());
                deviceInfo.setPersonFaceInfoList(null);
                return deviceInfo;
            }).collect(Collectors.toList());

            AbstractIntelligentEntranceGuardAccessor intelligentEntranceGuardAccessor = AccessorUtils.getIntelligentEntranceGuardAccessor(deviceTypeDto);
            intelligentEntranceGuardAccessor.authPerson(DeviceFaceSendCmd.builder()
                    .type(DeviceFaceSendCmd.TypeEnum.ADD.getType())
                    .deviceInfoList(list)
                    .build());
        }
        return idSet;
    }

    private String genQrCode(DeviceTypeDto deviceTypeDto, List<DeviceDto> deviceDtos) {
        AbstractIntelligentEntranceGuardAccessor intelligentEntranceGuardAccessor = AccessorUtils.getIntelligentEntranceGuardAccessor(deviceTypeDto);
        return intelligentEntranceGuardAccessor.genQrCode(DeviceQrCodeGenCmd.builder()
                .deviceUniqueIds(deviceDtos.stream().map(DeviceDto::getUniqueId).toArray(String[]::new))
                .personFaceInfo(null)
                .build());
    }
}
